配置参数

按照SIP标准,jssip.ua有必须和可选两种参数需要配置。例如:

var configuration = {

'ws_servers': 'wss://sip-ws.example.com',

'uri': 'sip:alice@example.com',

'password': 'superpassword'

};

var coolPhone = new JsSIP.UA(configuration);

下面分别说明各参数的含义和格式。

1)必须的参数

uri

用户的SIP URI地址(即SIP账号),格式类似Email(即“协议:名称@主机”),例如:

ws_servers

WebSocket服务器地址(WS URI),格式类似HTTP URL,例如:wss://192.168.4.224:8089/ws

2)可选的参数

authorization_user

字符串,指生成身份验证凭据时使用的用户名。如果未定义,则使用URI参数中的值。例如:authorization_user: 授权用户名

log

字符型,表示日志级别,取值为err、info或debug。例如:log: { level: 'err' }

connection_recovery_max_interval

整型,表示WebSocket重新连接最小尝试秒数。

connection_recovery_min_interval

整型,表示WebSocket重新连接最大尝试秒数。

display_name

字符串,指在被叫方的呼叫请求或发送即时消息中显示的描述性的名称。例如:display_name: myname

hack_ip_in_contact

布尔型,表示将随机IP地址设置为头字段中的主机值,并通过参数发送。用于SIP注册不允许的URI。有效值为true和false(布尔)。默认值为false。

hack_via_tcp

布尔型,表示是否将SIP的请求的传输协议设置为TCP,当不准备解析头部“WS”或“WSS”时有用。有效值为true和false(布尔)。默认值为false。

hack_via_ws

布尔型,当连接到一个安全的WebSocket服务器时(“WSS://”),指示是“通过WS而不是WSS”。当穿越HTTP / WebSocket代理作为TLS隧道时有用。有效值为true或false。默认值为false。

instance_id

no_answer_timeout

整型,表示呼叫请求的超时等待时间(单位:秒)。如果超过此时间没有应答,则自动结束通话请求。默认值是60。例如:no_answer_timeout: 45

session_timers 

布尔型,是否启用会话计时器(RFC 4028),默认值是true。

node_websocket_options

password

字符串,表示SIP授权密码。例如:password: sip_password

register

布尔型,表示JsSIP用户代理启动时是否自动注册,有效值为true和false(默认值为true)。例如:register: true

register_expires

整型,表示注册超时时间(单位:秒),默认值是600。例如:register_expires: 30

registrar_server

字符串,指SIP注册服务器的URI,有效值是一个没有用户名的SIP URI,默认值是NULL(表示注册URI是从用户的SIP URI参数提取的)。例如:registrar_server: 'sip:registrar.mydomain.com'

use_preloaded_route

布尔型,如果设置为TRUE,则在发送每个SIP会话的请求时由JsSIP包装一个相关联的WebSocket服务器作为SIP URI路由头。一些SIP Outbound代理要求这样的header。有效值为true和false(布尔)。默认值为false。

基本功能接口

基本功能接口的函数原型参见“gui.js”文件,主要提供用户登录,拨号,挂断等功能。

4.3.1 初始化环境

创建JSSIP.UA

原型 JsSIP.UA(configuration);
参数 configuration
返回值 JsSIP.UA对象。
说明 初始化JSSIP客户端代理
示例 configuration = { log: { level: 'err' },//log级别debug jerry uri: sip_uri, password: sip_password, ws_servers: ws_servers, display_name: display_name, authorization_user: authorization_user, register: register, register_expires: register_expires, registrar_server: registrar_server, no_answer_timeout: no_answer_timeout, session_timers: session_timers, use_preloaded_route: use_preloaded_route, connection_recovery_min_interval: connection_recovery_min_interval, connection_recovery_max_interval: connection_recovery_max_interval, hack_via_tcp: hack_via_tcp, hack_via_ws: hack_via_ws, hack_ip_in_contact: hack_ip_in_contact }; } try { ua = new JsSIP.UA(configuration); } catch(e) { console.log(e.toString()); Y_U_NO(e.message, 4000); return; }

启动WebSocket连接

函数原型 ua.start();
参数 无。
返回值
说明 W3CWebSocket创建,注册回调等。
示例 ua.start();

打开(关闭)调试信息

函数原型 JsSIP.debug.enable('JsSIP:*'); JsSIP.debug.disable('JsSIP:*');
参数
返回值 无。
说明 在浏览器控制台输出调试信息。
示例 JsSIP.debug.enable('JsSIP:*'); 可以在首页
4.3.2 事件响应

JsSIP的每一个事件处理程序是通过一个字符串参数值触发的,而这个字符串要用相同的对象或实例的侦听器通过on()方法安装。例如:

var ua = new JsSIP.UA( ... );

ua.on('newRTCSession', function(data) {

var originator = data.originator;

var session = data.session;

var request = data.request;

// Stop the UA. Note that `this` is bound to the `ua` instance.

this.stop();

});

JS事件主要分为用户代理事件(ua)和会话状态事件(call)。其中,前者主要用于报告用户账号的登录状态,后者主要用于报告通话的进行状态。

用户代理事件

Connected事件

原型 ua.on('connected', function(e) {…});
参数 'connected':字符串,表示已经连接到websocket服务器。 function(e) {…}:回调函数,连接上以后界面做一些处理。
返回值
说明 如果JSSIP连接上websocket服务器,会触发此回调
示例 // Transport connection/disconnection callbacks ua.on('connected', function(e) { document.title = PageTitle; GUI.setStatus("connected"); // Habilitar el phone. $("#phone .controls .ws-disconnected").hide(); ws_was_connected = true; });

Disconnected事件

原型 ua.on('disconnected', function(e) {…});
参数 'disconnected':字符串,表示断开连接到websocket服务器。 function(e) {…}:回调函数,断开以后界面做一些处理。
返回值 无。
说明 如果JSSIP断开连接websocket服务器,会触发此回调。
示例 ua.on('disconnected', function(e) { document.title = PageTitle; GUI.setStatus("disconnected"); // Deshabilitar el phone. $("#phone .controls .ws-disconnected").show(); // Eliminar todas las sessiones existentes. $("#sessions > .session").each(function(i, session) { GUI.removeSession(session, 500); }); if (! ws_was_connected) { //alert("WS connection error:\n\n- WS close code: " + e.data.code + "\n- WS close reason: " + e.data.reason); console.error("WS connection error | WS close code: " + e.code + " | WS close reason: " + e.reason); //if (! window.CustomJsSIPSettings) { window.location.reload(false); } } });

newRTCSession事件

原型 ua.on('newRTCSession', function(e) {…});
参数 'newRTCSession':字符串,表示新的会话产生。 function(e) {…}:回调,请在此做新会话的监听工作。
返回值
说明 新的会话(Session)将会发出一些事件,在回调里应该做监听处理,后面会说明会话(Session)需要监听那些事件。
示例 // Call/Message reception callbacks ua.on('newRTCSession', function(e) { // Set a global '_Session' variable with the session for testing. _Session = e.session; GUI.new_session(e) });

registered事件

原型 ua.on('registered', function(e){…});
参数 'registered': 字符串,表示已经注册到websocket服务器上 function(e){…}:
返回值
说明 客户端已经注册上服务器,可以随时发送SIP报文
示例 ua.on('registered', function(e){ console.info('Registered'); GUI.setStatus("registered"); if (invitedBy) { input[type='text']").val("Hi there, you have invited me to call you :)"); phone_dialed_number_screen.val(invitedBy); phone_chat_button.click(); var invited_session = GUI.getSession("sip:" + invitedBy + "@" + tryit_sip_domain); invitedBy = null; $(invited_session).find(".chat > input[type='text']").val("Hi there, wanna talk?"); var e = jQuery.Event("keydown"); e.which = 13 // Enter $(invited_session).find(".chat > input[type='text']").trigger(e); $(invited_session).find(".chat > input[type='text']").focus(); } });

unregistered事件

原型 ua.on('unregistered', function(e){…});
参数 'unregistered':字符串,表示反注册事件。 function(e){…}:回调,反注册成功后在此显示一些提示
返回值
说明 请在此处进行反注册后的回调处理
示例 ua.on('unregistered', function(e){ console.info('Deregistered'); GUI.setStatus("connected"); });

registrationFailed事件

原型 ua.on('registrationFailed', function(e) {…});
参数 'registrationFailed':字符串,表示注册失败。
返回值
说明 注册失败时回调
示例 ua.on('registrationFailed', function(e) { console.info('Registration failure'); GUI.setStatus("connected"); if (! e.response) { // alert("SIP registration error:\n" + e.data.cause); } else { // alert("SIP registration error:\n" + e.data.response.status_code.toString() + " " + e.data.response.reason_phrase) } // if (! window.CustomJsSIPSettings) { window.location.reload(false); } });

会话状态事件

Progress事件

原型 call.on('progress',function(e){…});
参数 'progress':字符串,表示呼叫正在处理。 function(e){…}:回调,可进行界面处理。
返回值 无。
说明 呼叫正在处理,可以显示一些提示信息。
示例 // Progress call.on('progress',function(e){ if (e.originator === 'remote') { GUI.setCallSessionStatus(session, 'in-progress'); } });

Accepted事件

原型 call.on('accepted',function(e){…});
参数 'accepted':字符串,表示对方已经应答。 function(e){…}:回调,可以显示一些界面提示。
返回值 无。
说明 如果已经应答,则回调,用来提示通话已经开始。
示例 call.on('accepted',function(e){ var streamIdx, trackIdx, streamsLength, tracksLength, tracks, localStreams = call.connection.getLocalStreams(); streamsLength = localStreams.length; //alert(streamsLength); for (streamIdx = 0; streamIdx < streamsLength; streamIdx++) { tracks = localStreams[streamIdx].getAudioTracks(); tracksLength = tracks.length; for (trackIdx = 0; trackIdx < tracksLength; trackIdx++) { tracks[trackIdx].enabled = false; } } //Attach the streams to the views if it exists. if (call.connection.getLocalStreams().length > 0) { localStream = call.connection.getLocalStreams()[0]; selfView = JsSIP.rtcninja.attachMediaStream(selfView, localStream); selfView.volume = 0; } if (e.originator === 'remote') { if (e.response.getHeader('X-Can-Renegotiate') === 'false') { call.data.remoteCanRenegotiateRTC = false; } else { call.data.remoteCanRenegotiateRTC = true; } } GUI.setCallSessionStatus(session, 'answered'); });

Addstream事件

函数原型 call.on('addstream', function(e) {…});
参数 'addstream':字符串,表示流已经开始接收。 function(e) {…}:回调,收到流以后的处理。
返回值
说明 通过此回调把流放到合适的地方,音频自动处理,这里如果不涉及视频可忽略。
示例 call.on('addstream', function(e) { console.log('Tryit: addstream()'); remoteStream = e.stream; remoteView = JsSIP.rtcninja.attachMediaStream(remoteView, remoteStream); });

Failed事件

函数原型 call.on('failed',function(e) {…});
参数 'failed':字符串,表示会话产生未知错误; function(e) {…}:回调,请在此处对错误进行简单提示。
返回值
说明 开始拨号后产生错误,请在此适当处理
示例 call.on('failed',function(e) { var cause = e.cause, response = e.response; if (e.originator === 'remote' && cause.match("SIP;cause=200", "i")) { cause = 'answered_elsewhere'; } GUI.setCallSessionStatus(session, 'terminated', cause); soundPlayer.setAttribute("src", "sounds/outgoing-call-rejected.wav"); soundPlayer.play(); GUI.removeSession(session, 1500); selfView.src = ''; remoteView.src = ''; _Session = null; });

newDTMF事件(保留)

hold事件(保留)

unhold事件(保留)

ended事件

函数原型 call.on('ended',function(e) {…});
参数 'ended':字符串,表示会话结束; function(e) {…}:回调,请在此处进行简单提示。
返回值
说明 挂断后在这里做一些提示
示例 call.on('ended', function(e) { var cause = e.cause; GUI.setCallSessionStatus(session, "terminated", cause); GUI.removeSession(session, 1500); selfView.src = ''; remoteView.src = ''; _Session = null; JsSIP.rtcninja.closeMediaStream(localStream); });

update事件(保留)

reinvite事件(保留)

4.3.3 注册

注册

原型 ua.register();
参数 空。
返回值 无。
说明 向websocket服务器注册。
示例 ua.register();

取消注册

原型 ua.unregister(object);
参数 Object:json对象,可为空。
返回值
说明 向websocket服务器反注册。
示例 ua.unregister({'all': true});

通话功能接口

4.4.1 静音

静音

原型 tracks[trackIdx].enabled;
说明 关闭本地流。
示例 var streamIdx, trackIdx, streamsLength, tracksLength, tracks, localStreams = call.connection.getLocalStreams(); streamsLength = localStreams.length; for (streamIdx = 0; streamIdx < streamsLength; streamIdx++) { tracks = localStreams[streamIdx].getAudioTracks(); tracksLength = tracks.length; for (trackIdx = 0; trackIdx < tracksLength; trackIdx++) { tracks[trackIdx].enabled = false; } }

取消静音

原型 tracks[trackIdx].enabled;
说明 打开本地流。
示例 var streamIdx, trackIdx, streamsLength, tracksLength, tracks, localStreams = call.connection.getLocalStreams(); streamsLength = localStreams.length; for (streamIdx = 0; streamIdx < streamsLength; streamIdx++) { tracks = localStreams[streamIdx].getAudioTracks(); tracksLength = tracks.length; for (trackIdx = 0; trackIdx < tracksLength; trackIdx++) { tracks[trackIdx].enabled = true; } }
4.4.2 拨号
原型 ua.call(target, {…});
参数 target:字符串,会议室号码。 {…}:json对象,用来设置拨号参数,具体请看示例。
返回值
说明
示例 ua.call(target, { pcConfig: peerconnection_config, mediaConstraints: { audio: true,DtlsSrtpKeyAgreement: false, video:false }, extraHeaders: [ 'X-Can-Renegotiate: ' + String(localCanRenegotiateRTC()) ], rtcOfferConstraints: { offerToReceiveAudio: 1, offerToReceiveVideo: 1, DtlsSrtpKeyAgreement: 0 } }); 注:peerconnection_config 可以这样写:{ "iceServers": [], "gatheringTimeout": 2000 },参考DEMO。
4.4.3 挂断
原型 session.call.terminate();
参数 无。
返回值
说明 挂断是通过会话session调用dialogs完成的。
示例 button_hangup.click(function() { GUI.setCallSessionStatus(session, "terminated", "terminated"); session.call.terminate(); GUI.removeSession(session, 500); });

其它

下面红色字体部分需要添加到HTML页面中,这些JS文件主要实现sip协议的封装、事件注册和界面提示功能,例如:拨号,挂断等。

//打开调试,关闭请用JsSIP.debug.disable("*")

//下面判断浏览器是否支持 WebRTC 以及浏览器适配,请根据需要添加提示信息